package com.randb.easyhttp.interceptor;

import android.text.TextUtils;

import com.randb.easyhttp.utils.HttpLog;
import com.randb.easyhttp.utils.HttpUtil;
import com.randb.easyhttp.utils.Utils;

import org.jetbrains.annotations.NotNull;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;

import okhttp3.FormBody;
import okhttp3.HttpUrl;
import okhttp3.Interceptor;
import okhttp3.MultipartBody;
import okhttp3.Request;
import okhttp3.Response;

/**
 * User: RandBII
 * Date: 2020/5/15
 * Description:
 */
public abstract class BaseDynamicInterceptor<R extends BaseDynamicInterceptor> implements Interceptor {

    private HttpUrl httpUrl;
    private boolean isSign = false;
    private boolean timeStamp = false;
    private boolean accessToken = false;

    public BaseDynamicInterceptor() {

    }


    public boolean isSign() {
        return isSign;
    }

    public R sign(boolean sign) {
        this.isSign = sign;
        return (R) this;
    }

    @NotNull
    @Override
    public Response intercept(@NotNull Chain chain) throws IOException {

        Request request = chain.request();
        if ("GET".equals(request.method())) {
            this.httpUrl = HttpUrl.parse(parseUrl(request.url().url().toString()));
            try {
                request = addGetParamsSign(request);
            } catch (Exception e) {
                e.printStackTrace();
            }
        } else if ("POST".equals(request.method())) {
            this.httpUrl = request.url();
            request = addPostParamsSign(request);
        }

        return chain.proceed(request);
    }

    private Request addPostParamsSign(Request request) throws UnsupportedEncodingException {

        if (request.body() instanceof FormBody) {
            FormBody.Builder builder = new FormBody.Builder();
            FormBody body = (FormBody) request.body();
            TreeMap<String, String> oldParams = new TreeMap<>();
            for (int i = 0; i < body.size(); i++) {
                oldParams.put(body.encodedName(i), body.encodedValue(i));
            }

            TreeMap<String, String> newParams = dynamic(oldParams);
            Utils.checkNotNull(newParams, " Params is null");

            for (Map.Entry<String, String> param : newParams.entrySet()) {
                String value = URLDecoder.decode(param.getValue(), HttpUtil.UTF8.name());
                builder.addEncoded(param.getKey(), value);
            }
            String url = HttpUtil.createUrlFromParams(httpUrl.url().toString(), newParams);
            HttpLog.i(url);
            body = builder.build();
            request = request.newBuilder().post(body).build();
        } else if (request.body() instanceof MultipartBody) {
            MultipartBody multipartBody = (MultipartBody) request.body();
            MultipartBody.Builder multipartBodyBuilder = new MultipartBody
                    .Builder().setType(MultipartBody.FORM);
            List<MultipartBody.Part> oldParts = new ArrayList<>();
            List<MultipartBody.Part> newParts = new ArrayList<>(oldParts);
            TreeMap<String, String> oldParams = new TreeMap<>();
            TreeMap<String, String> newParams = dynamic(oldParams);
            for (Map.Entry<String, String> stringStringEntry : newParams.entrySet()) {
                MultipartBody.Part part = MultipartBody.Part
                        .createFormData(stringStringEntry.getKey(), stringStringEntry.getValue());
                newParts.add(part);
            }

            for (MultipartBody.Part part : newParts) {
                multipartBodyBuilder.addPart(part);
            }
            multipartBody = multipartBodyBuilder.build();
            request = request.newBuilder().post(multipartBody).build();

        }

        return request;

    }


    private Request addGetParamsSign(Request request) throws Exception {

        HttpUrl httpUrl = request.url();
        HttpUrl.Builder builder = httpUrl.newBuilder();
        Set<String> names = httpUrl.queryParameterNames();
        ArrayList<String> nameList = new ArrayList<String>();
        nameList.addAll(names);
        TreeMap<String, String> treeMap = new TreeMap<>();

        for (int i = 0; i < nameList.size(); i++) {
            String value = httpUrl.queryParameterValues(nameList.get(i)) != null
                    && httpUrl.queryParameterValues(nameList.get(i)).size() > 0 ?
                    httpUrl.queryParameterValues(nameList.get(i)).get(0) : "";
            treeMap.put(nameList.get(i), value);
        }
        String nameKeys = Collections.singletonList(nameList).toString();
        TreeMap<String, String> newParam = dynamic(treeMap);
        Utils.checkNotNull(newParam, "new Params == null");

        for (Map.Entry<String, String> entry : newParam.entrySet()) {
            String urlValue = URLEncoder.encode(entry.getValue(), HttpUtil.UTF8.name());
            if (!nameKeys.contains(entry.getValue())) {
                builder.addQueryParameter(entry.getKey(), urlValue);
            }
        }

        httpUrl = builder.build();
        request = request.newBuilder().url(httpUrl).build();
        return request;


    }


    public abstract TreeMap<String, String> dynamic(TreeMap<String, String> treeMap);


    private String parseUrl(String url) {
        if (!"".equals(url) && url.contains("?")) {
            url = TextUtils.substring(url, 0, url.indexOf("?"));
        }
        return url;
    }


    public boolean isTimeStamp() {
        return timeStamp;
    }

    public R timeStamp(boolean timeStamp) {
        this.timeStamp = timeStamp;
        return (R) this;
    }


    public boolean isAccessToken() {
        return accessToken;
    }

    public R accessToken(boolean accessToken) {
        this.accessToken = accessToken;
        return (R) this;
    }


}
